package system.train;

import system.communication.Monitor;
import system.track.Block;
import system.track.Direction;
import system.ui.Engine;
/**
 * The generic Train class. A Train is the virtual representation of a physical
 * train on the track.
 * 
 * @author Yasmine  
 */

public class Train extends Thread
{
   private Block currentBlock;
   private Route currentRoute;
   protected boolean waiting;
   private boolean running;
   private int speed;
   private Direction currentDirection;
   private int id;

   /**
    * @param block
    * @param id
    */
   public Train(Block block, int id)
   {
       currentBlock = block;
       waiting = false;
       running = true;
       speed = 0;
       this.id = id;
   }

   /**
    * @return the id registered to this train
    */
   public int getID()
   {
       return id;
   }

   /**
    * Gives a route to the train based on the direction input.
    *
    * @param direction A direction to base the route on.
    */
   public synchronized void setRoute(Direction direction)
   {
       currentRoute = Route.createRoute(direction);
   }

   /**
    *
    * @return boolean based on if the train is currently running.
    */
    protected boolean isRunning()
    {
        return running;
    }

    /**
     * Sets the current direction to the input given.
     *
     * @param direction to set the train to.
     */
   public synchronized void setDirection(Direction direction)
   {
       currentDirection = direction;
       Engine.getInstance().postTrainDirection(id, direction);
   }

   /**
    * Gets the current direction of the train.
    *
    * @return the current direction of the train.
    */
   public Direction getDirection()
   {
       return currentDirection;
   }

    /**
     * Gets the current block where the train resides.
     *
     * @return the current Block of the train.
     */
   public Block getCurrentBlock()
   {
       return currentBlock; 
   }

   /**
    * Sets the current block of the train to the input given.
    *
    * @param block to set the train to.
    */
   public synchronized void setCurrentBlock(Block block)
   {
       currentBlock = block;
       Engine.getInstance().postTrainReservations(id, getReservedBlocks());
   }

   /**
    * Retreives an integer array containing the current blocks that the train is
    * currently reserving.
    *
    * @return array of int id's of the current blocks reserved by the train.
    */
   public int[] getReservedBlocks()
   {
       return new int[] {currentBlock.getID()};
   }

   /**
    * Gets the current speed of the train.
    *
    * @return the current speed of the train.
    */
   public int getSpeed()
   {
       return speed;
   }


   /**
    * Sets the current speed of the train to the input.
    *
    * @param speed
    */
   public synchronized void setSpeed(int speed)
   {
       if(speed > 0 || speed < 7)
       {
            this.speed = speed;
       }
   }

   /**
    * Kills the train thread.
    */
   public synchronized void kill()
   {
       running = false;
       pause();
       tripSensor();
   }

   /**
    * Stops the train.
    */
   public synchronized void pause()
   {
       RouteActions.STOP.executeAction(this);
   }

   /**
    * Notifies the train that it has tripped a sensor.
    */
   public synchronized void tripSensor()
   {
       this.waiting = false;
       try
       {
            Thread.sleep(2000);
       }
       catch(InterruptedException e)
       {
           System.out.println(e.getMessage());
           e.printStackTrace();
       }
       notify();
   }

   /**
    * Puts the train thread on a wait.
    */
   protected synchronized void waitForSensor()
   {
       try
       {
           while(waiting)
           {
               wait();
           }
       }
       catch(InterruptedException e)
       {
           System.out.println("TRAIN THREAD WAS INTERRUPTED!  WTF??");
           e.printStackTrace();
       }
   }

   /**
    * Runs the train thread
    */
   @Override
   public void run()
   {
       while(running)
       {
           while(!waiting && running)
           {
               waiting = currentRoute.executeNextAction(this);
           }
           waitForSensor();
       }
   }

   /**
    *
    * @return boolean value based on whether the train is controlled by a
    * handcontroller.
    */
   public boolean isHandControlled()
   {
       return false;
   }
}
